<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> 
    <title> - 天地维杰网</title>
    <meta name="keywords" content="系统架构,shutdown,不与天斗,Domino,博客,程序员,架构师,笔记,技术,分享,java,Redis">
    
    <meta property="og:title" content="">
    <meta property="og:site_name" content="天地维杰网">
    <meta property="og:image" content="/img/author.jpg"> 
    <meta name="title" content=" - 天地维杰网" />
    <meta name="description" content="天地维杰网 | 博客 | 软件 | 架构 | Java "> 
    <link rel="shortcut icon" href="http://www.shutdown.cn/img/favicon.ico" />
    <link rel="apple-touch-icon" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link rel="apple-touch-icon-precomposed" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link href="http://www.shutdown.cn/js/vendor/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/main.css" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/syntax.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Pisces',
    sidebar: {"position":"left","display":"post"},
     fancybox: true, 
    motion: true
  };
</script>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7826003325059020" crossorigin="anonymous"></script>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container one-collumn sidebar-position-left page-home  ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"> <div class="site-meta  custom-logo ">

  <div class="custom-logo-site-title">
    <a href="http://www.shutdown.cn"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">天地维杰网</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">人如秋鸿来有信，事若春梦了无痕</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
    <ul id="menu" class="menu">
      
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />首页
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/redis/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-battery-full"></i> <br />Redis
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/java/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-coffee"></i> <br />java
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/linux/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-linux"></i> <br />linux
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/daily/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bug"></i> <br />日常问题
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/spring/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-child"></i> <br />Spring和Springboot
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/mac/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-fire"></i> <br />Mac相关
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/middleware/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-gavel"></i> <br />中间件
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jiagou/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-rocket"></i> <br />架构
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/python/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-ship"></i> <br />python
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/front/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bolt"></i> <br />前端
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jvm/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-balance-scale"></i> <br />jvm
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/c/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-battery-empty"></i> <br />c语言
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/web3/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-web3"></i> <br />web3
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/post/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />归档
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/about/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />关于
          </a>
        </li>
      
      <li class="menu-item menu-item-search">
        <a href="javascript:;" class="popup-trigger"> <i class="menu-item-icon fa fa-search fa-fw"></i> <br /> 搜索</a>
      </li>
    </ul>
    <div class="site-search">
      <div class="popup">
 <span class="search-icon fa fa-search"></span>
 <input type="text" id="local-search-input">
 <div id="local-search-result"></div>
 <span class="popup-btn-close">close</span>
</div>

    </div>
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
<section id="posts" class="posts-expand">
  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <header class="post-header">
      <h1 class="post-title" itemprop="name headline">
        <a class="post-title-link" href="http://www.shutdown.cn/post/springboot-event%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%80%BB%E7%BB%93/" itemprop="url">
        
        </a>
      </h1>
      <div class="post-meta">
      <span class="post-time">
<span class="post-meta-item-icon">
    <i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">时间：</span>
<time itemprop="dateCreated" datetime="2016-03-22T13:04:35+08:00" content="0001-01-01">
    0001-01-01
</time>
</span> 
      
      
       <span>
&nbsp; | &nbsp;
<span class="post-meta-item-icon">
    <i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读：</span>
<span class="leancloud-visitors-count">700 字 ~4分钟</span>
</span>
      </div>
    </header>
    <div class="post-body" itemprop="articleBody">
    

    

<h1 id="springboot-event线程池总结">springboot event线程池总结</h1>

<p>事件是达到解藕目的的手段之一。</p>

<p>最近项目出了一个线上故障，就是因事件引起的，有必要进行一次对事件知识点的梳理</p>

<p>现在公司都是使用的spring全家桶，所以技术面都会在spring boot，这方面我也是新手了，学习与总结并进，新旧知识连贯</p>

<p>此文包含几个知识点</p>

<ol>
<li>事件实现原理</li>
<li>事件使用的几种方式事件，达到解藕目的的手段之一</li>
</ol>

<p>最近项目出了一个线上故障，就是因事件引起的，有必要进行一次对事件知识点的梳理</p>

<p>事件是引子，背后还是线程池的知识点</p>

<p>说来也搞笑，在面试时，几轮面试官都问了线程池问题，说明此公司肯定有过线程池的事故，要么大家统一对线程池有了高度认知，却不然遇到的第一个故障就是线程池引起的</p>

<p>可见面试与实现差距有多大</p>

<p>现在公司都是使用的spring全家桶，所以技术面都会在spring boot，这方面我也是新手了，学习与总结并进，新旧知识连贯</p>

<p>此文包含几个知识点</p>

<ol>
<li>事件实现原理</li>
<li>事件使用的几种方式</li>
<li>异步事件</li>
<li>故障始末</li>
</ol>

<h2 id="原理">原理</h2>

<p>事件实现原理其实就是个观察者模式，所以也没什么好说的</p>

<h2 id="实现方式">实现方式</h2>

<p>此处实现都以spring boot为基础，约定大于配置，所以在spring boot项目中，配置文件大大减少，相对以前写大量代码、配置文件还真是不习惯，感觉苦日子过惯了，还真是不习惯，感觉心里不踏实</p>

<p>达到一个事件，需要三件东西：event、publisher、listener</p>

<p>而在spring boot中，使用几个注解就可以</p>

<h3 id="注解方式">注解方式</h3>

<p>最常见最普通的事件</p>

<h4 id="事件">事件</h4>

<p>一个简单的类</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a40000">@</span><span style="color:#000">Data</span>
<span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">class</span> <span style="color:#000">DemoEvent</span>  <span style="color:#000;font-weight:bold">{</span>


    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#000">DemoEvent</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87">String</span> <span style="color:#000">data</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">eventData</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">data</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>

    <span style="color:#204a87;font-weight:bold">private</span> <span style="color:#204a87">String</span> <span style="color:#000">eventData</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<h4 id="监听者">监听者</h4>

<p>一个简单的bean，再加上一个@EventListener，还有所在方法的参数是所需要监听的事件</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a40000">@</span><span style="color:#000">Component</span>
<span style="color:#a40000">@</span><span style="color:#000">Slf4j</span>
<span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">class</span> <span style="color:#000">DemoEventListener</span> <span style="color:#000;font-weight:bold">{</span>

    <span style="color:#a40000">@</span><span style="color:#000">EventListener</span>
    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">void</span> <span style="color:#000">demoEventListener</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">DemoEvent</span> <span style="color:#000">demoEvent</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">{</span>
        <span style="color:#000">log</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">info</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;demoevent listener,eventValue:{},order=2&#34;</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">demoEvent</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getEventData</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>

    <span style="color:#000;font-weight:bold">}</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<h4 id="发布者">发布者</h4>

<p>spring已经有了现成的ApplicationEventPublisher,而ApplicationContext就是实现者，因此只要是spring容器，都会有个context</p>

<h3 id="实现监听接口">实现监听接口</h3>

<p>发布者不变了，事件与监听者换一种方式</p>

<h4 id="监听者-1">监听者</h4>

<p>实现ApplicationListener接口</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a40000">@</span><span style="color:#000">Component</span>
<span style="color:#a40000">@</span><span style="color:#000">Slf4j</span>
<span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">class</span> <span style="color:#000">DemoEventApplictionListener</span> <span style="color:#204a87;font-weight:bold">implements</span> <span style="color:#000">ApplicationListener</span><span style="color:#ce5c00;font-weight:bold">&lt;</span><span style="color:#000">AppEvent</span><span style="color:#ce5c00;font-weight:bold">&gt;</span> <span style="color:#000;font-weight:bold">{</span>

    <span style="color:#a40000">@</span><span style="color:#000">Override</span>
    <span style="color:#8f5902;font-style:italic">//@Async
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#a40000">@</span><span style="color:#000">Order</span><span style="color:#000;font-weight:bold">(</span><span style="color:#0000cf;font-weight:bold">3</span><span style="color:#000;font-weight:bold">)</span>
    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">void</span> <span style="color:#000">onApplicationEvent</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">AppEvent</span> <span style="color:#000">demoEvent</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#000">log</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">info</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;listener value:{},order=3&#34;</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">demoEvent</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getEventData</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>

<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<h4 id="事件-1">事件</h4>

<p>因为使用了ApplicationListener，所以事件需要是ApplicationEvent的子类</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a40000">@</span><span style="color:#000">Data</span>
<span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">class</span> <span style="color:#000">AppEvent</span> <span style="color:#204a87;font-weight:bold">extends</span> <span style="color:#000">org</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">springframework</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">context</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">ApplicationEvent</span> <span style="color:#000;font-weight:bold">{</span>


    <span style="color:#204a87;font-weight:bold">private</span> <span style="color:#204a87">String</span> <span style="color:#000">eventData</span><span style="color:#000;font-weight:bold">;</span>


    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#000">AppEvent</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87">String</span> <span style="color:#000">source</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">super</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">source</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>

        <span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">eventData</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">source</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<h3 id="有顺序监听者">有顺序监听者</h3>

<p>一个事件，可以有很多监听者，这些监听者需要按执行顺序执行</p>

<p>此时，监听者实现SmartApplicationListener,此接口中有getOrder()</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a40000">@</span><span style="color:#000">Component</span>
<span style="color:#a40000">@</span><span style="color:#000">Slf4j</span>
<span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">class</span> <span style="color:#000">DemoEventSmartApplicationListener</span> <span style="color:#204a87;font-weight:bold">implements</span> <span style="color:#000">SmartApplicationListener</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#a40000">@</span><span style="color:#000">Override</span>
    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">boolean</span> <span style="color:#000">supportsEventType</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">Class</span><span style="color:#ce5c00;font-weight:bold">&lt;</span><span style="color:#ce5c00;font-weight:bold">?</span> <span style="color:#204a87;font-weight:bold">extends</span> <span style="color:#000">ApplicationEvent</span><span style="color:#ce5c00;font-weight:bold">&gt;</span> <span style="color:#000">aClass</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">aClass</span> <span style="color:#ce5c00;font-weight:bold">==</span> <span style="color:#000">AppEvent</span><span style="color:#000;font-weight:bold">.</span><span style="color:#204a87;font-weight:bold">class</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>

    <span style="color:#a40000">@</span><span style="color:#000">Override</span>
    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">boolean</span> <span style="color:#000">supportsSourceType</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">Class</span><span style="color:#ce5c00;font-weight:bold">&lt;</span><span style="color:#ce5c00;font-weight:bold">?</span><span style="color:#ce5c00;font-weight:bold">&gt;</span> <span style="color:#000">aClass</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#204a87;font-weight:bold">true</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>

    <span style="color:#a40000">@</span><span style="color:#000">Override</span>
    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">int</span> <span style="color:#000">getOrder</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>

    <span style="color:#a40000">@</span><span style="color:#000">Override</span>
    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#204a87;font-weight:bold">void</span> <span style="color:#000">onApplicationEvent</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">ApplicationEvent</span> <span style="color:#000">applicationEvent</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#000">AppEvent</span> <span style="color:#000">event</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">AppEvent</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000">applicationEvent</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">log</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">info</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;smartapplicationListener,value:{},order=1&#34;</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">event</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getEventData</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<p>其实还有@Order注解，也是一样的，并不一定要实现此接口</p>

<h2 id="异步事件">异步事件</h2>

<p>在此前的实现方式都是同步的，虽然解藕，但对性能没有多大提升</p>

<p>异步事件就不一样了，有时使用就是为了不拖累主流程</p>

<p>要达到异步，使用两个注解</p>

<p>一在入口使用@EnableAsync,二是在监听方法上加上@Async</p>

<h3 id="异步线程">异步线程</h3>

<p>使用异步，那必然是需要线程池的。到此没有配置线程池，因此需要关注一下默认的线程池是什么样的</p>

<p>对于spring boot的异步实现原理在<strong>AsyncExecutionAspectSupport</strong>类中，实现方法：</p>

<p>获取Executor</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#204a87;font-weight:bold">protected</span> <span style="color:#000">AsyncTaskExecutor</span> <span style="color:#000">determineAsyncExecutor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">Method</span> <span style="color:#000">method</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#000">AsyncTaskExecutor</span> <span style="color:#000">executor</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">executors</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">get</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">method</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">executor</span> <span style="color:#ce5c00;font-weight:bold">==</span> <span style="color:#204a87;font-weight:bold">null</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
            <span style="color:#000">Executor</span> <span style="color:#000">targetExecutor</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87">String</span> <span style="color:#000">qualifier</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">getExecutorQualifier</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">method</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">StringUtils</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">hasLength</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">qualifier</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#000">targetExecutor</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">findQualifiedExecutor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">beanFactory</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">qualifier</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#204a87;font-weight:bold">else</span> <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#000">targetExecutor</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">defaultExecutor</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">get</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">targetExecutor</span> <span style="color:#ce5c00;font-weight:bold">==</span> <span style="color:#204a87;font-weight:bold">null</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#204a87;font-weight:bold">null</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#000">executor</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">targetExecutor</span> <span style="color:#204a87;font-weight:bold">instanceof</span> <span style="color:#000">AsyncListenableTaskExecutor</span> <span style="color:#ce5c00;font-weight:bold">?</span>
                    <span style="color:#000;font-weight:bold">(</span><span style="color:#000">AsyncListenableTaskExecutor</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000">targetExecutor</span> <span style="color:#ce5c00;font-weight:bold">:</span> <span style="color:#204a87;font-weight:bold">new</span> <span style="color:#000">TaskExecutorAdapter</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">targetExecutor</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">executors</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">put</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">method</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">executor</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000;font-weight:bold">}</span>
        <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">executor</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<p>没有配置qualifier,取默认线程池</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#204a87;font-weight:bold">protected</span> <span style="color:#000">Executor</span> <span style="color:#000">getDefaultExecutor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#a40000">@</span><span style="color:#000">Nullable</span> <span style="color:#000">BeanFactory</span> <span style="color:#000">beanFactory</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">beanFactory</span> <span style="color:#ce5c00;font-weight:bold">!=</span> <span style="color:#204a87;font-weight:bold">null</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">try</span> <span style="color:#000;font-weight:bold">{</span>
            <span style="color:#8f5902;font-style:italic">// Search for TaskExecutor bean... not plain Executor since that would
</span><span style="color:#8f5902;font-style:italic"></span>            <span style="color:#8f5902;font-style:italic">// match with ScheduledExecutorService as well, which is unusable for
</span><span style="color:#8f5902;font-style:italic"></span>            <span style="color:#8f5902;font-style:italic">// our purposes here. TaskExecutor is more clearly designed for it.
</span><span style="color:#8f5902;font-style:italic"></span>            <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">beanFactory</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getBean</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">TaskExecutor</span><span style="color:#000;font-weight:bold">.</span><span style="color:#204a87;font-weight:bold">class</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000;font-weight:bold">}</span>
        <span style="color:#204a87;font-weight:bold">catch</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">NoUniqueBeanDefinitionException</span> <span style="color:#000">ex</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
            <span style="color:#000">logger</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">debug</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;Could not find unique TaskExecutor bean&#34;</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">ex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">try</span> <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">beanFactory</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getBean</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">DEFAULT_TASK_EXECUTOR_BEAN_NAME</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">Executor</span><span style="color:#000;font-weight:bold">.</span><span style="color:#204a87;font-weight:bold">class</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#204a87;font-weight:bold">catch</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">NoSuchBeanDefinitionException</span> <span style="color:#000">ex2</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">logger</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">isInfoEnabled</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
                    <span style="color:#000">logger</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">info</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;More than one TaskExecutor bean found within the context, and none is named &#34;</span> <span style="color:#ce5c00;font-weight:bold">+</span>
                            <span style="color:#4e9a06">&#34;&#39;taskExecutor&#39;. Mark one of them as primary or name it &#39;taskExecutor&#39; (possibly &#34;</span> <span style="color:#ce5c00;font-weight:bold">+</span>
                            <span style="color:#4e9a06">&#34;as an alias) in order to use it for async processing: &#34;</span> <span style="color:#ce5c00;font-weight:bold">+</span> <span style="color:#000">ex</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getBeanNamesFound</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
                <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#000;font-weight:bold">}</span>
        <span style="color:#000;font-weight:bold">}</span>
        <span style="color:#204a87;font-weight:bold">catch</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">NoSuchBeanDefinitionException</span> <span style="color:#000">ex</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
            <span style="color:#000">logger</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">debug</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;Could not find default TaskExecutor bean&#34;</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">ex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">try</span> <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">beanFactory</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getBean</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">DEFAULT_TASK_EXECUTOR_BEAN_NAME</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">Executor</span><span style="color:#000;font-weight:bold">.</span><span style="color:#204a87;font-weight:bold">class</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#204a87;font-weight:bold">catch</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">NoSuchBeanDefinitionException</span> <span style="color:#000">ex2</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#000">logger</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">info</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;No task executor bean found for async processing: &#34;</span> <span style="color:#ce5c00;font-weight:bold">+</span>
                        <span style="color:#4e9a06">&#34;no bean of type TaskExecutor and no bean named &#39;taskExecutor&#39; either&#34;</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#8f5902;font-style:italic">// Giving up -&gt; either using local default executor or none at all...
</span><span style="color:#8f5902;font-style:italic"></span>        <span style="color:#000;font-weight:bold">}</span>
    <span style="color:#000;font-weight:bold">}</span>
    <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#204a87;font-weight:bold">null</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<p>在TaskExecutionAutoConfiguration中有默认的线程池配置了</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a40000">@</span><span style="color:#000">Lazy</span>
    <span style="color:#a40000">@</span><span style="color:#000">Bean</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">name</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">{</span> <span style="color:#000">APPLICATION_TASK_EXECUTOR_BEAN_NAME</span><span style="color:#000;font-weight:bold">,</span>
            <span style="color:#000">AsyncAnnotationBeanPostProcessor</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">DEFAULT_TASK_EXECUTOR_BEAN_NAME</span> <span style="color:#000;font-weight:bold">}</span><span style="color:#000;font-weight:bold">)</span>
    <span style="color:#a40000">@</span><span style="color:#000">ConditionalOnMissingBean</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">Executor</span><span style="color:#000;font-weight:bold">.</span><span style="color:#204a87;font-weight:bold">class</span><span style="color:#000;font-weight:bold">)</span>
    <span style="color:#204a87;font-weight:bold">public</span> <span style="color:#000">ThreadPoolTaskExecutor</span> <span style="color:#000">applicationTaskExecutor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">TaskExecutorBuilder</span> <span style="color:#000">builder</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">builder</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">build</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<h3 id="springboot1">springboot1</h3>

<p>在springboot1版本中，其实没有默认线程池的，在springboot2之后才有，可以看release-notes</p>

<blockquote>
<p>Task Execution Spring Boot now provides auto-configuration for ThreadPoolTaskExecutor. If you are using @EnableAsync, your custom TaskExecutor can be removed in favor of customizations available from the spring.task.execution namespace. Custom ThreadPoolTaskExecutor can be easily created using TaskExecutorBuilder.</p>
</blockquote>

<p>那么在springboot1中默认使用了哪个线程池呢？</p>

<p>在AsyncExecutionInterceptor中</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a40000">@</span><span style="color:#000">Override</span>
<span style="color:#a40000">@</span><span style="color:#000">Nullable</span>
<span style="color:#204a87;font-weight:bold">protected</span> <span style="color:#000">Executor</span> <span style="color:#000">getDefaultExecutor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#a40000">@</span><span style="color:#000">Nullable</span> <span style="color:#000">BeanFactory</span> <span style="color:#000">beanFactory</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#000">Executor</span> <span style="color:#000">defaultExecutor</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87;font-weight:bold">super</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">getDefaultExecutor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">beanFactory</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">defaultExecutor</span> <span style="color:#ce5c00;font-weight:bold">!=</span> <span style="color:#204a87;font-weight:bold">null</span> <span style="color:#ce5c00;font-weight:bold">?</span> <span style="color:#000">defaultExecutor</span> <span style="color:#ce5c00;font-weight:bold">:</span> <span style="color:#204a87;font-weight:bold">new</span> <span style="color:#000">SimpleAsyncTaskExecutor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<p>可以看出如果没有配置线程池，就是SimpleAsyncTaskExecutor</p>

<p>这个类注释讲得很清楚</p>

<blockquote>
<p>{@link TaskExecutor} implementation that fires up a new Thread for each task,executing it asynchronously.</p>
</blockquote>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#204a87;font-weight:bold">protected</span> <span style="color:#204a87;font-weight:bold">void</span> <span style="color:#000">doExecute</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">Runnable</span> <span style="color:#000">task</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#000">Thread</span> <span style="color:#000">thread</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">threadFactory</span> <span style="color:#ce5c00;font-weight:bold">!=</span> <span style="color:#204a87;font-weight:bold">null</span> <span style="color:#ce5c00;font-weight:bold">?</span> <span style="color:#204a87;font-weight:bold">this</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">threadFactory</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">newThread</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">task</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">:</span> <span style="color:#000">createThread</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">task</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000">thread</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">start</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div>
<p>有任务时，就是新建线程</p>

<hr />

<h3 id="线程池">线程池</h3>

<p>事件本身没有太多的知识点，但对于线程池，需要再温习一下，在后面的故障分析中，关键知识点还是线程池</p>

<p>对于线程池的理解，从习得第一印象，认为线程池其实是对于线程与任务两者合并的消费生产者模式</p>

<p>但如果面试中，面试官询问如何理解线程池的？我也不会这样回答，这涉及到两人对于知识的共振范围，最好谈一些共识最大的点，利在于不踩坑，弊在于平凡不起眼</p>

<p>自jdk5开始，JDK引入了concurrent包,也就是大名鼎鼎的JUC，其中最常见ThreadPoolExecutor</p>

<p>常规知识点，线程池的几个重要参数</p>

<ol>
<li>核心线程数：corePoolSize</li>
<li>最大线程数: maxPoolSize</li>
<li>线程空间时长: keepAliveTime</li>
<li>核心线程超时: allowCoreThreadTimeout,默认值false,若为true,空闲时，线程池中会没有线程</li>
<li>任务队列: workQueue</li>
<li>拒绝处理器: rejectedExecutionHandler</li>
</ol>

<p>自带拒绝策略</p>

<ul>
<li>AbortPolicy:默认策略，丢弃任务，抛RejectedExecutionException异常</li>
<li>DiscardPolicy:丢弃任务，但不抛异常</li>
<li>DiscardOldestPolicy:丢弃队列最前面的任务，然后重新尝试执行任务</li>
<li>CallerRunsPolicy:由调用线程处理任务</li>
</ul>

<p>线程池的工作原理，网上有很多资料，提交任务给线程池，大致流程：</p>

<ol>
<li>当线程池中线程数量小于 corePoolSize 则创建线程，并处理请求</li>
<li>当线程池中线程数量大于等于 corePoolSize 时，则把请求放入 workQueue中,随着线程池中的核心线程们不断执行任务，只要线程池中有空闲的核心线程，线程池就从 workQueue 中取任务并处理</li>
<li>当 taskQueue 已存满，放不下新任务时则新建非核心线程入池，并处理请求直到线程数目达到 maximumPoolSize（最大线程数量设置值）</li>
<li>如果线程池中线程数大于 maximumPoolSize 则使用 RejectedExecutionHandler 来进行任务拒绝处理</li>
</ol>

<h4 id="参数设定">参数设定</h4>

<p>在日常使用过程中，需要关注的是各参数数值设定，那么如何设定呢？</p>

<p>一、线程数越多越好吗？</p>

<p>这个明显不是，比如单核CPU，设置上万个线程没有意义；而且线程过多，上下文切换，反而降低性能</p>

<p>这儿引出一个问题，单核能多线程吗？</p>

<blockquote>
<p>进程是资源的基本单位，线程是cpu调度的基本单位</p>
</blockquote>

<p>如果一个线程一直占用CPU，那肯定多线程无用，但总有等待时候，如IO，此时，多线程就有了用武之地</p>

<p>线程数小了，显示又达不到最大化CPU性能</p>

<p>二、队列容量越大越好吗？</p>

<p>显然也不是，常人都关注线程数的设定，但队列大小鲜有人问，如果队列过大，积压相当多的任务，必然导致响应时间过长</p>

<p>如果队列过小，甚至没有，那任务没有缓冲，可能造成线程快速扩张</p>

<p>线程数与队列容量得配合使用，怎么才是合理的参数呢？</p>

<p>最直接的方式，模拟线上请求进行压测，随着请求量增加，QPS上升，当到了一定的阀值之后，请求数量增加QPS并不会增加，或者增加不明显，同时请求的响应时间却大幅增加。这个阀值我们认为是最佳线程数</p>

<p>对于线程数量多少，有很多的设定理论依据</p>

<h5 id="任务类型">任务类型</h5>

<p>以任务类型设定,这是常用来粗略估值的</p>

<ul>
<li>IO密集型</li>
<li>CPU密集型</li>
</ul>

<p>如果是IO密集型，一般是CPU数*2；IO密集型CPU使用率不高，可以让CPU等待IO的时候处理别的任务，充分利用CPU</p>

<p>如果是CPU密集型 ，一般是CPU数+1；CPU使用率高，若开过多线程，增加线程上下文切换次数，带来额外开销</p>

<h5 id="公式">公式</h5>

<p>前人早就有了计算公式</p>

<p><strong>一、《Java Concurrency in Practice》</strong></p>

<p>这本书中作者给出了定义</p>

<div  align="center"><img src="https://wejack639.oss-cn-beijing.aliyuncs.com/blogimages/img/20220316170648.png" width = 600 /> </div>

<p>比如平均每个线程CPU运行时间为0.5s，而线程等待时间（非CPU运行时间，比如IO）为1.5s，CPU核心数为8，那么根据上面这个公式估算得到：8 * (1+(1.<sup>5</sup>&frasl;<sub>0</sub>.5)=32</p>

<p><strong>二、《Programming Concurrency on the JVM Mastering》</strong></p>

<p>线程数=Ncpu/（1-阻塞系数）：其中计算密集型阻塞系数为0，IO密集型阻塞系数接近1：</p>

<div  align="center"><img src="https://wejack639.oss-cn-beijing.aliyuncs.com/blogimages/img/20220316170703.png" width = 900 /> </div>

<p>如果以这个示例使用第一个公式计算：2 * (1+(0.<sup>9</sup>&frasl;<sub>0</sub>.1)) =20,结果也是20</p>

<p>可以这么思考：两个公式表达不同，但实质一致</p>

<p>即Ncpu/（1-阻塞系数）=Ncpu*(1+w/c)</p>

<p>则<strong>阻塞系数=w/(w+c)</strong>，阻塞系数=阻塞时间/（阻塞时间+计算时间）</p>

<p>以第二个公式计算第一公式中的示例：8 / (1-(1.5/(1.5+0.5))) = 32</p>

<p>这样两个公式计算出的结果就是一样的</p>

<p>以公式计算法推算任务类型分类方式：</p>

<ul>
<li>IO型：w/c≈1，公式算出2*cpu</li>
<li>CPU型：w/c≈0,公式算出1*cpu</li>
</ul>

<p>公式的方法有了，如何确定公式中的变量值呢？</p>

<p>最原始的办法打印日志，等待CPU时间无非就是db,io,网络调用，在发包前，发包后打上日志，算得时间差，求出平均值</p>

<p><strong>三、其它公式</strong></p>

<blockquote>
<p>设置的线程数 = 目标QPS/(1/任务实际处理时间) = QPS*每个任务处理时间</p>
</blockquote>

<p>(核心线程就以平均qps定；最大线程就以最高qps定)</p>

<p>举例说明，假设目标QPS=100，任务实际处理时间0.2s，100 * 0.2 = 20个线程，这里的20个线程必须对应物理的20个CPU核心，否则将不能达到预估的QPS指标</p>

<blockquote>
<p>队列大小 = 线程数 * (最大响应时间/任务实际处理时间)</p>
</blockquote>

<p>假设目标最大响应时间为0.4s，计算阻塞队列的长度为20 * (0.4 / 0.2) = 40</p>

<p>这个公式有点难以理解，最初的公式应该是</p>

<blockquote>
<p>线程数/任务实际处理时间 * 响应时间 = 队列大小</p>
</blockquote>

<p>类似 速度*时间=长度</p>

<hr />

<p>这么多的公式，死记硬背是不行的，简单理解一下，qps是每秒处理任务数，如果一个线程处理是1s，那么多少qpS，就需要多少线程了,若是处理0.2s，那1s可以处理5个任务了，也就是1/0.2，那线程数只需要qps/5了，也就是公式qps/(1/任务处理时间)</p>

<h2 id="故障描述">故障描述</h2>

<p>有了上面的知识储备，现在回顾一下整个故障过程</p>

<h3 id="起因">起因</h3>

<p>项目中使用的是springboot1,鉴于上面的线程实现，同事认为每次异步事件都是新创建线程，是很不合理的，这个不用讲，是的确很不合适，放着线程池不用，却使用最原始的新建线程。所以需要优化，使用线程池</p>

<h3 id="过程">过程</h3>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#204a87;font-weight:bold">private</span> <span style="color:#000">Integer</span> <span style="color:#000">corePoolSize</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">8</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#204a87;font-weight:bold">private</span> <span style="color:#000">Integer</span> <span style="color:#000">maxPoolSize</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">40</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#204a87;font-weight:bold">private</span> <span style="color:#000">Integer</span> <span style="color:#000">queueCapacity</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">200</span><span style="color:#000;font-weight:bold">;</span>
</code></pre></div>
<p>设置了线程池参数，因为机器是4核，所以就cpu*2,分析认为请求不多，所以看这个配置也没有大过</p>

<h3 id="表象">表象</h3>

<p>发了版本之后，发现了问题，发现线上业务数据都不对，感觉所有的请求都失败了。</p>

<p>通过日志发现，请求正常进来了，但异步事件业务都没有正常执行执行到</p>

<h3 id="分析">分析</h3>

<p>由结果来复盘整个事件，事件之中处理出了很多的问题，罗列一些，以鉴未来</p>

<p>1、全局性配置不可轻动</p>

<p>现在的系统是个遗留系统，业务复杂，代码交错。就是个正常健壮系统都不能随意变更，更何况现在不稳定，也没有理清根节，万不可动</p>

<p>动也得不仅有理论基础，还得实操配合，压力测试不可缺少</p>

<p>也得必须留有后手，如开关，如此次线程池没有配置拒绝策略</p>

<p>2、处理故障第一要务</p>

<p>发布后出现问题，再所难免，但一旦出现故障不是去分析故障，而是马上恢复业务提供能力：回滚</p>

<p>现在都是基于容器，完全就是留一台保留事故现场，留做后期分期</p>

<p>而不是放任故障蔓延，不停地分析争论原因</p>

<p>当然，回滚动作比较大，可以设置开关，这次更大问题是，开关有了，结果没有测试完备，没有生效</p>

<p>3、基础知识扎实</p>

<p>此次在处理事故中，开始不清楚springboot1的默认线程池，以为是默认的CachedThreadPool,在开关失效时，想通过修改线程池配置来修复问题，同事一直强调CPU就4核，设置大了，系统跟不上，也让我烦躁了，结果错乱地指挥把队列设置了无限大，更加加大了任务的延迟</p>

<p>线程的数量的确不宜过大，但也没说只能最大2*CPU,为CPU核数的2倍，为CPU核数的8倍，为CPU核数的32倍,法无定法</p>

    </div>
    <footer class="post-footer">
     

     <div class="post-nav">
    <div class="post-nav-next post-nav-item">
    
        <a href="http://www.shutdown.cn/post/redis%E9%9B%AA%E5%B4%A9%E6%95%88%E5%BA%94%E7%9A%84%E5%8E%9F%E5%9B%A0%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/" rel="next" title="">
        <i class="fa fa-chevron-left"></i> 
        </a>
    
    </div>

    <div class="post-nav-prev post-nav-item">
    
        <a href="http://www.shutdown.cn/post/springboot-%E5%90%AF%E5%8A%A8%E6%89%A9%E5%B1%95%E7%82%B9/" rel="prev" title="">
         <i class="fa fa-chevron-right"></i>
        </a>
    
    </div>
</div>
      
     
     
     






    </footer>
  </article>
</section>

          </div>
        </div>
        <div class="sidebar-toggle">
  <div class="sidebar-toggle-line-wrap">
    <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
  </div>
</div>
<aside id="sidebar" class="sidebar">
  <div class="sidebar-inner">

    <section class="site-overview sidebar-panel  sidebar-panel-active ">
      <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image"
        src="http://www.shutdown.cn/img/author.jpg"
        alt="不与天斗Domino" />
    <p class="site-author-name" itemprop="name">不与天斗Domino</p>
    <p class="site-description motion-element" itemprop="description"> 
        Programmer &amp; Architect</p>
</div>
      <nav class="site-state motion-element">
    <div class="site-state-item site-state-posts">
      <a href="http://www.shutdown.cn/post/">
        <span class="site-state-item-count">183</span>
        <span class="site-state-item-name">日志</span>
      </a>
    </div>
    <div class="site-state-item site-state-categories">    
        <a href="http://www.shutdown.cn/categories/">      
         
        <span class="site-state-item-count">15</span>
        
        <span class="site-state-item-name">分类</span>
        
        </a>
    </div>

    <div class="site-state-item site-state-tags">
        <a href="http://www.shutdown.cn/tags/">
         
        <span class="site-state-item-count">224</span>
        
        <span class="site-state-item-name">标签</span>
        </a>
    </div>
</nav>
      
      

      

      <div class="links-of-blogroll motion-element inline">
<script type="text/javascript" src="//rf.revolvermaps.com/0/0/8.js?i=&amp;m=0&amp;s=220&amp;c=ff0000&amp;cr1=ffffff&amp;f=arial&amp;l=33&amp;bv=35" async="async"></script>
</div>

    </section>
    
  </div>
</aside>

      </div>
    </main>
   
    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  <span itemprop="copyrightYear">  &copy; 
  2013 - 2023</span>
  <span class="with-love"><i class="fa fa-heart"></i></span>
  <span class="author" itemprop="copyrightHolder">天地维杰网</span>
  <span class="icp" itemprop="copyrightHolder"><a href="https://beian.miit.gov.cn/" target="_blank">京ICP备13019191号-1</a></span>
</div>
<div class="powered-by">
  Powered by - <a class="theme-link" href="http://gohugo.io" target="_blank" title="hugo" >Hugo v0.63.2</a>
</div>
<div class="theme-info">
  Theme by - <a class="theme-link" href="https://github.com/xtfly/hugo-theme-next" target="_blank"> NexT
  </a>
</div>


      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
      <span id="scrollpercent"><span>0</span>%</span>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/fastclick/lib/fastclick.min.js?v=1.0.6"></script> 
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script src="http://www.shutdown.cn/js/vendor/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>

<script src="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.pack.js?v=2.1.5"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/utils.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/motion.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/affix.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/schemes/pisces.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/scrollspy.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/post-details.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/toc.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/bootstrap.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ['$','$'] ],
      displayMath: [ ['$$','$$'] ],
      processEscapes: true
    },
    "HTML-CSS": { fonts: ["TeX"] }
  });
</script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML' async></script>
</body>
</html>